#include "character.h"

#include "engine.h"
#include "items.h"
#include "maps.h"

#include <boost/serialization/list.hpp>

using namespace fortress;

character::character():
AI(1), aiController(0)
{
	setCoords(0,0);
}

character::character(int setStrength, int setIntelligence, int setDexterity, int setConstitution, int setCharisma, int setLuck, bool setAI):
	hp(5),
	maxHp(5),
	AI(setAI),
	aiController(0)
{
	setStats(setStrength, setIntelligence, setDexterity, setConstitution, setCharisma, setLuck);
}

character::~character()
{
	for(std::list<items*>::iterator it = inventory.begin(); it!=inventory.end(); it++)
	{
		delete *it;
	}
	inventory.clear();
}

void character::setStats(int setStrength, int setIntelligence, int setDexterity, int setConstitution, int setCharisma, int setLuck)
{
	strength = setStrength;
	intelligence = setIntelligence;
	dexterity = setDexterity;
	constitution = setConstitution;
	charisma = setCharisma;
	luck = setLuck;
}

bool character::move(int moveX, int moveY)
{
	if (moveX == 0 && moveY == 0)
		return 0;
	int curX,curY;
	getCoords(curX,curY);
	int newX = curX + moveX;
	int newY = curY + moveY;
	// check to see if that movement was valid
	if (newX >= 0 && newX < 80 && newY>=0 && newY < 23)
	{
		// Probably going to make a "walkable" list for the purposes of magical boots or something
		char getTile = currentMap->getTile(newX, newY);
		if (getTile=='.' || getTile=='#')
		{
			// If there is a character here, interpret it as an attack
			eventReceiver * target = currentMap->getCharacter(newX,newY);
			if (target)
			{
				// just do some damage for testing
				//target->exec(event_attack,3);
				eventStructure attackEvent(this, this, event_attack,3,newX,newY);
				currentMap->fireEventOnTile(attackEvent);
				return 1;
			}
			else if (!currentMap->getBlocked(newX,newY))
			{
				setCoords(newX,newY);
				return 1;
			}
		}
	}
	return 0;
}

bool character::exec(int a, int b)
{
	switch(a)
	{
	case event_attack:
//		receiveAttack(b);
		break;
	}
	return 0;
}

bool character::doEvent(eventStructure const & sent)
{
	switch(sent.type)
	{
	case event_attack: // make this character defend itself
		receiveAttack(sent.degree);
		return 1;
	}
	return 0;
}

void character::kill()
{
	// Tell the AI priority list to take us off, then set the pointer to null
	if (aiController)
		aiController->remove(this);
	aiController=0;
}

bool character::pickupItem()
{
	int a,b;
	getCoords(a,b);
	std::list<items*> const * tempList = currentMap->getItemList(a,b);
	if (tempList==0)
		return 0;
	items * tempItem = tempList->front();
	if (!tempItem->getCanCarry())
		return 0;
	inventory.push_back(tempItem);
	currentMap->pickupItem(a,b,tempItem);
	return 1;
}

bool character::dropItem()
{
	int a,b;
	getCoords(a,b);
	if (inventory.begin()==inventory.end())
		return 0;
	items * tempItem = inventory.front();
	inventory.remove(tempItem);
	tempItem->setCoords(a,b);
	currentMap->dropItem(*tempItem);
	return 0;
}

bool character::useStairs(bool upstairs)
{
	int a,b;
	getCoords(a,b);
	map * newMap = currentMap;
	if (currentMap->travelPortal(a,b,upstairs,newMap))
	{
		currentMap->releaseCharacter(this);
		newMap->putCharacter(this);
		setCoords(a,b);
		setMap(newMap);
		return 1;
	}
	return 0;
}

bool character::receiveAttack(int damage)
{
	adjustHealth(damage*-1);
	if (hp<=0)
	{
		kill();
		currentMap->mergeItemList(inventory); // drop all items
		currentMap->killCharacter(this);
	}
	return 1;
}

void character::setHealth(int newHp, int newMaxHp)
{
	hp=newHp;
	if (newMaxHp==0)
		maxHp=hp;
	else
		maxHp=newMaxHp;
}

void character::adjustHealth(int amt)
{
	hp+=amt;
	if (hp>maxHp)
		hp=maxHp;
	if (hp<0)
		hp=0;
}

template<class Archive>
void character::serialize(Archive & ar, const unsigned int version)
{
	ar & boost::serialization::base_object<glyph>(*this);
	ar & hp & maxHp & mp & maxMp & strength & intelligence & dexterity & constitution & charisma & luck
		& AI;// << inventory;
	ar & inventory;
	ar & aiController;
}

template void character::serialize<boost::archive::binary_oarchive>(boost::archive::binary_oarchive & ar, const unsigned int version);
template void character::serialize<boost::archive::text_oarchive>(boost::archive::text_oarchive & ar, const unsigned int version);
template void character::serialize<boost::archive::text_iarchive>(boost::archive::text_iarchive & ar, const unsigned int version);